package db

import (
	"GameServer/common"
	"GameServer/common/logger"
	jconf "GameServer/jsonconfig"
	"GameServer/pb"
	"GameServer/redis"
	"encoding/json"
	"errors"
	"strconv"
	"sync"
	"time"
)

type SiginInfo struct {
	Uuid          int32
	Sign_day      int32 //签到天数
	Is_signed     int32 //是否已经签到
	Sign_state    int32 //签到是否已经完成 0否1是
	Last_signtime int32 //上一次签到时间
}

type UserBaseInfo struct {
	Uuid        int32
	User_star   int32 //星星
	User_dimond int32 //美钞
	User_tili   int32 //体力
	Plan_num    int32 //飞机数量
	Boom_num    int32 //飞机数量
	Rainbow_num int32 //飞机数量
	Cur_level   int32 //飞机数量
	Sync_id     int64 //同步包id
}

//对应dtb_user_extratask
type UserExtraTaskInfo struct {
	Uuid       int32
	New_taskid int32
	User_data  string
}

//dtb_user_deviceinfo
type UserDeviceInfo struct {
	Uuid           int32
	Device_uuid    string
	Create_time    int32
	Last_logintime int32
	Login_type     int32
	Token          string
}

//dtb_user_signdata
type UserSignData struct {
	Uuid          int32
	Sign_day      int32
	Is_signed     int32
	Sign_state    int32
	Last_signtime int32
}

func GetUserBaseInfo(uuid uint32) (*UserBaseInfo, error) {
	// *******************************
	if redis.GetRedisIsOpen() {
		baseinfo := new(UserBaseInfo)
		val, err := redis.GetRedisClient().HGet(redis.GS_USERBASE_INFO, strconv.Itoa(int(uuid)))
		if err != nil {
			logger.Error("GetUserBaseInfo failed err=%v", err)
			return nil, err
		}
		err = json.Unmarshal([]byte(val), baseinfo)
		if err != nil {
			logger.Error("GetUserBaseInfo json failed err=%v", err)
			return nil, err
		}

		return baseinfo, nil
	}
	// *******************************

	baseinfo := new(UserBaseInfo)
	row := m_game_db.QueryRow("select uuid,user_gold,user_dimond,user_tili,plan_num,boom_num,rainbow_num,cur_level,syncid "+
		"from dtb_user_main where uuid = ? ", uuid)
	err := row.Scan(&baseinfo.Uuid, &baseinfo.User_star, &baseinfo.User_dimond, &baseinfo.User_tili, &baseinfo.Plan_num,
		&baseinfo.Boom_num, &baseinfo.Rainbow_num, &baseinfo.Cur_level, &baseinfo.Sync_id)

	if err != nil {
		logger.Error("GetUserBaseInfo failed err=%v", err)
		return nil, err
	}
	return baseinfo, nil
}

func UpdateUserBaseInfo(uuid uint32, info *UserBaseInfo) error {
	if info == nil {
		logger.Error("UpdateUserBaseInfo info nil")
		return errors.New("UpdateUserBaseInfo info nil")
	}

	// *******************************
	if redis.GetRedisIsOpen() {
		val, err := json.Marshal(info)
		if err != nil {
			logger.Error("UpdateUserBaseInfo err=%v", err)
			return err
		}

		err = redis.GetRedisClient().HSet(redis.GS_USERBASE_INFO, strconv.Itoa(int(uuid)), string(val))

		if err != nil {
			logger.Error("UpdateUserBaseInfo err=%v", err)
			return err
		}
		return nil
	}
	// *******************************

	cmd := "update dtb_user_main set user_gold = ?,user_dimond = ?,user_tili = ?,plan_num = ?,boom_num = ?,rainbow_num = ?,cur_level = ? where uuid = ?"
	_, err := m_game_db.Query(cmd, info.User_star, info.User_dimond, info.User_tili, info.Plan_num, info.Boom_num, info.Rainbow_num, info.Cur_level, uuid)
	if err != nil {
		logger.Error("UpdateUserBaseInfo err=%v", err)
		return err
	}
	return nil
}

func GetUserRecentQuestid(uuid uint32) int32 {
	var receneid int32

	// *******************************
	if redis.GetRedisIsOpen() {
		baseinfo := new(UserExtraTaskInfo)
		val, err := redis.GetRedisClient().HGet(redis.GS_USEREXTRA_DATA, strconv.Itoa(int(uuid)))
		if err != nil {
			logger.Error("GetUserRecentQuestid failed err=%v", err)
			return 0
		}
		err = json.Unmarshal([]byte(val), baseinfo)
		if err != nil {
			logger.Error("GetUserRecentQuestid json failed err=%v", err)
			return 0
		}

		return baseinfo.New_taskid
	}
	// *******************************

	row := m_game_db.QueryRow("select newest_taskid from dtb_user_extratask where uuid = ? ", uuid)

	err := row.Scan(&receneid)

	if err != nil {
		logger.Error("GetUserRecentQuestid failed err=%v", err)

	}
	return receneid
}

func GetUserInfo(uuid uint32) (int32, int32, int32, int32, int64) {
	var gold, dimond, tili, cur_level int32
	var syncid int64

	// *******************************
	if redis.GetRedisIsOpen() {
		baseinfo := new(UserBaseInfo)
		val, err := redis.GetRedisClient().HGet(redis.GS_USERBASE_INFO, strconv.Itoa(int(uuid)))
		if err != nil {
			logger.Error("GetUserInfo failed err=%v", err)
			return 0, 0, 0, 0, 0
		}
		err = json.Unmarshal([]byte(val), baseinfo)
		if err != nil {
			logger.Error("GetUserInfo json failed err=%v", err)
			return 0, 0, 0, 0, 0
		}

		return baseinfo.User_star, baseinfo.User_dimond, baseinfo.User_tili, baseinfo.Cur_level, baseinfo.Sync_id
	}
	// *******************************

	row := m_game_db.QueryRow("select user_gold,user_dimond,user_tili,cur_level,syncid from dtb_user_main where uuid = ? ", uuid)

	err := row.Scan(&gold, &dimond, &tili, &cur_level, &syncid)

	if err != nil {
		logger.Error("GetUserInfo failed err=%v", err)

	}

	return gold, dimond, tili, cur_level, syncid
}

func TokenAccess(uuid uint32, token string) bool {

	// *******************************
	if redis.GetRedisIsOpen() {
		baseinfo := new(UserDeviceInfo)
		val, err := redis.GetRedisClient().HGet(redis.GS_USERDEVICE_INFO, strconv.Itoa(int(uuid)))
		if err != nil {
			logger.Error("TokenAccess failed err=%v", err)
			return false
		}
		err = json.Unmarshal([]byte(val), baseinfo)
		if err != nil {
			logger.Error("TokenAccess json failed err=%v", err)
			return false
		}

		return baseinfo.Token == token
	}
	// *******************************

	cnt := 0
	row := m_game_db.QueryRow("select count(*) from dtb_user_deviceinfo where uuid = ? and login_token= ?", uuid, token)

	err := row.Scan(&cnt)

	if err != nil || cnt == 0 {
		logger.Error("TokenAccess failed err=%v,cnt=%v", err, cnt)
		return false
	}

	return true
}

func GetUuid(deviceuuid string) (int, error) {
	uuid := 0
	row := m_game_db.QueryRow("select uuid from dtb_user_deviceinfo where device_uuid = ?", deviceuuid)

	err := row.Scan(&uuid)

	if err != nil {
		logger.Info("GetUuid error:%v", err)
		return 0, err
	}

	return uuid, nil
}

func UpdateLogin(uuid int) error {
	nowt := time.Now().Unix()
	_, err := m_game_db.Exec("update dtb_user_deviceinfo set last_logintime= ? where uuid=?", nowt, uuid)
	if err != nil {
		logger.Info("Register error:%v", err)
		return err
	}

	return nil
}

func Register(deviceuuid string) (int, error) {
	nowt := time.Now().Unix()
	//插入登录表
	_, err := m_game_db.Exec("insert into dtb_user_deviceinfo (device_uuid, create_time,last_logintime,login_token) values(?, ?,?,?)", deviceuuid, nowt, nowt, "")
	if err != nil {
		return 0, err
	}

	uuid := 0
	row := m_game_db.QueryRow("select uuid from dtb_user_deviceinfo where device_uuid = ?", deviceuuid)

	err = row.Scan(&uuid)
	if err != nil {
		logger.Info("Register error:%v", err)
		return 0, err
	}

	//插入玩家主表基础数据
	_, err = m_game_db.Exec("insert into dtb_user_main (uuid, user_data) values(?, ?)", uuid, "")
	if err != nil {
		logger.Info("Register error:%v", err)
		return 0, err
	}

	return uuid, nil
}

func LoadPlayerFromDB(uid int) (*common.GamePlayer, error) {
	//	cmd := `select  COALESCE(id,0), COALESCE(mobile,''), COALESCE(passwd,''), COALESCE(avatar,''), COALESCE(avatar_thumb,''),
	//                COALESCE(nick_name,''), COALESCE(gender,0), COALESCE(user_marks,''), COALESCE(diamond_num,0), COALESCE(user_gold,0),
	//                COALESCE(games_max,0), COALESCE(clubs_max,0), COALESCE(current_games,0), COALESCE(current_clubs,0), COALESCE(point,0),
	//                COALESCE(reg_code,''), COALESCE(sale_code,''), COALESCE(card_type,0), COALESCE(token,''), COALESCE(device_type,0),
	//                COALESCE(reg_time,0),  COALESCE(last_login,0), COALESCE(is_online,0), COALESCE(room_id,0) from dtb_user_main `

	// *******************************
	if redis.GetRedisIsOpen() {
		baseinfo := new(UserBaseInfo)
		val, err := redis.GetRedisClient().HGet(redis.GS_USERBASE_INFO, strconv.Itoa(int(uid)))
		if err != nil {
			logger.Error("GetUserBaseInfo failed err=%v", err)
			return nil, err
		}
		err = json.Unmarshal([]byte(val), baseinfo)
		if err != nil {
			logger.Error("GetUserBaseInfo json failed err=%v", err)
			return nil, err
		}

		player := new(common.GamePlayer)
		player.UID = uid
		player.ConnLocker = new(sync.RWMutex)
		player.OutChannel = make(chan []byte, 32)
		player.OutDone = make(chan bool)
		player.LastAt = time.Now().Unix()
		return player, nil
	}
	// *******************************
	cmd := "select uuid from dtb_user_main where uuid = " + strconv.Itoa(uid)
	rows, err := m_game_db.Query(cmd)
	if rows != nil {
		defer rows.Close()
	}
	if err != nil {
		logger.Info("LoadPlayerFromDB Query error:%v cmd:%v", err, cmd)
		return nil, err
	}
	for rows.Next() {
		var id int
		err = rows.Scan(&id)
		if err != nil {
			logger.Notic("LoadPlayerFromDB scan error:%v", err)
			return nil, err
		}

		logger.Info("id:%v", id)

		player := new(common.GamePlayer)
		player.UID = uid
		player.ConnLocker = new(sync.RWMutex)
		player.OutChannel = make(chan []byte, 32)
		player.OutDone = make(chan bool)
		player.LastAt = time.Now().Unix()
		return player, nil
	}
	err = common.ErrorsNotFoundPlayerInMysql
	return nil, err
}

func UpdateToken(token string, uuid int) error {

	_, err := m_game_db.Exec("update dtb_user_deviceinfo set login_token= ? where uuid=?", token, uuid)
	if err != nil {
		logger.Info("UpdateToken error:%v", err)
		return err
	}

	return nil
}

func GetGameUrl(gameid int32) (string, error) {
	gameurl := ""
	row := m_game_db.QueryRow("select game_url from dtb_game_list where gameid = ?", gameid)

	err := row.Scan(&gameurl)

	if err != nil {
		logger.Info("GetGameUrl error:%v", err)
		return gameurl, err
	}

	return gameurl, nil
}

func GetSignInfo(uid uint32) *SiginInfo {
	rt := new(SiginInfo)

	// *******************************
	if redis.GetRedisIsOpen() {

		val, err := redis.GetRedisClient().HGet(redis.GS_USERSIGN_DATA, strconv.Itoa(int(uid)))
		if err != nil {
			logger.Error("GetSignInfo failed err=%v", err)
			return nil
		}
		err = json.Unmarshal([]byte(val), rt)
		if err != nil {
			logger.Error("GetSignInfo json failed err=%v", err)
			return nil
		}

		return rt
	}
	// *******************************

	rt.Uuid = int32(uid)
	row := m_game_db.QueryRow("select sign_day,is_signed,sign_state,last_signtime from dtb_user_signdata where uuid = ?", uid)
	err := row.Scan(&rt.Sign_day, &rt.Is_signed, &rt.Sign_state, &rt.Last_signtime)

	if err != nil {
		logger.Notic("GetSingInfo error:%v", err)
		return nil
	}
	return rt
}

func UpdateSignInfo(sinfo *SiginInfo) error {

	// *******************************
	if redis.GetRedisIsOpen() {
		val, err := json.Marshal(sinfo)
		if err != nil {
			logger.Error("UpdateSignInfo err=%v", err)
			return err
		}

		err = redis.GetRedisClient().HSet(redis.GS_USERSIGN_DATA, strconv.Itoa(int(sinfo.Uuid)), string(val))

		if err != nil {
			logger.Error("UpdateSignInfo err=%v", err)
			return err
		}
		return nil
	}
	// *******************************

	_, err := m_game_db.Exec("update dtb_user_signdata set sign_day= ?,is_signed=?,sign_state=?,last_signtime=? where uuid = ?",
		sinfo.Sign_day, sinfo.Is_signed, sinfo.Sign_state, sinfo.Last_signtime, sinfo.Uuid)
	if err != nil {
		logger.Notic("UpdateSingInfo err=%+v", err)
		return err
	}
	return nil
}

func RewardSign(uid uint32, cfg *jconf.SignInfo) error {

	// *******************************
	if redis.GetRedisIsOpen() {
		baseinfo := new(UserBaseInfo)
		val, err := redis.GetRedisClient().HGet(redis.GS_USERBASE_INFO, strconv.Itoa(int(uid)))
		if err != nil {
			logger.Error("RewardSign failed err=%v", err)
			return err
		}
		err = json.Unmarshal([]byte(val), baseinfo)
		if err != nil {
			logger.Error("RewardSign json failed err=%v", err)
			return err
		}

		if cfg.ItemID == common.Enum_Item_Coin {
			baseinfo.User_star += cfg.RewardNum

		} else if cfg.ItemID == common.Enum_Item_Tili {
			baseinfo.User_tili += cfg.RewardNum
		} else if cfg.ItemID == common.Enum_Item_USD {
			baseinfo.User_dimond += cfg.RewardNum
		} else if cfg.ItemID == common.Enum_Item_Plane {
			baseinfo.Plan_num += cfg.RewardNum
		} else if cfg.ItemID == common.Enum_Item_Boom {
			baseinfo.Boom_num += cfg.RewardNum
		} else if cfg.ItemID == common.Enum_Item_RainBow {
			baseinfo.Rainbow_num += cfg.RewardNum
		} else {
			logger.Notic("RewardSign cfg.ItemID failed cfg=%v", *cfg)
			return errors.New("ItemID invalid")
		}

		newval, err := json.Marshal(baseinfo)
		if err != nil {
			logger.Error("RewardSign err=%v", err)
			return err
		}

		err = redis.GetRedisClient().HSet(redis.GS_USERBASE_INFO, strconv.Itoa(int(uid)), string(newval))

		if err != nil {
			logger.Error("RewardSign err=%v", err)
			return err
		}
		return nil
	}
	// *******************************

	cmd := ""
	if cfg.ItemID == common.Enum_Item_Coin {
		cmd = "update dtb_user_main set user_gold = user_gold + ? where uuid = ?"
		_, err := m_game_db.Exec(cmd, cfg.RewardNum, uid)
		if err != nil {
			logger.Notic("RewardSign failed err=%v", err)
			return err
		}

	} else if cfg.ItemID == common.Enum_Item_Tili {
		cmd = "update dtb_user_main set user_tili = user_tili + ? where uuid = ?"
		_, err := m_game_db.Exec(cmd, cfg.RewardNum, uid)
		if err != nil {
			logger.Notic("RewardSign failed err=%v", err)
			return err
		}
	} else if cfg.ItemID == common.Enum_Item_USD {
		cmd = "update dtb_user_main set user_dimond = user_dimond + ? where uuid = ?"
		_, err := m_game_db.Exec(cmd, cfg.RewardNum, uid)
		if err != nil {
			logger.Notic("RewardSign failed err=%v", err)
			return err
		}
	} else if cfg.ItemID == common.Enum_Item_Plane {
		cmd = "update dtb_user_main set plan_num = plan_num + ? where uuid = ?"
		_, err := m_game_db.Exec(cmd, cfg.RewardNum, uid)
		if err != nil {
			logger.Notic("RewardSign failed err=%v", err)
			return err
		}
	} else if cfg.ItemID == common.Enum_Item_Boom {
		cmd = "update dtb_user_main set boom_num = boom_num + ? where uuid = ?"
		_, err := m_game_db.Exec(cmd, cfg.RewardNum, uid)
		if err != nil {
			logger.Notic("RewardSign failed err=%v", err)
			return err
		}
	} else if cfg.ItemID == common.Enum_Item_RainBow {
		cmd = "update dtb_user_main set rainbow_num = rainbow_num + ? where uuid = ?"
		_, err := m_game_db.Exec(cmd, cfg.RewardNum, uid)
		if err != nil {
			logger.Notic("RewardSign failed err=%v", err)
			return err
		}
	} else {
		logger.Notic("RewardSign cfg.ItemID failed cfg=%v", *cfg)
		return errors.New("ItemID invalid")
	}
	return nil
}

func RewardTaskGruop(uid uint32, rids, rnum []int32) error {
	if len(rnum) < len(rids) {
		return errors.New("RewardTaskGruop param invalid")
	}

	// *******************************
	if redis.GetRedisIsOpen() {
		baseinfo := new(UserBaseInfo)
		val, err := redis.GetRedisClient().HGet(redis.GS_USERBASE_INFO, strconv.Itoa(int(uid)))
		if err != nil {
			logger.Error("RewardSign failed err=%v", err)
			return err
		}
		err = json.Unmarshal([]byte(val), baseinfo)
		if err != nil {
			logger.Error("RewardSign json failed err=%v", err)
			return err
		}

		for i := 0; i < len(rids); i++ {
			if rids[i] == common.Enum_Item_Coin {
				baseinfo.User_star += rnum[i]

			} else if rids[i] == common.Enum_Item_Tili {
				baseinfo.User_tili += rnum[i]
			} else if rids[i] == common.Enum_Item_USD {
				baseinfo.User_dimond += rnum[i]
			} else if rids[i] == common.Enum_Item_Plane {
				baseinfo.Plan_num += rnum[i]
			} else if rids[i] == common.Enum_Item_Boom {
				baseinfo.Boom_num += rnum[i]
			} else if rids[i] == common.Enum_Item_RainBow {
				baseinfo.Rainbow_num += rnum[i]
			} else {
				logger.Notic("RewardSign cfg.ItemID failed cfg=%v", rnum)
				continue
			}
		}

		newval, err := json.Marshal(baseinfo)
		if err != nil {
			logger.Error("RewardSign err=%v", err)
			return err
		}

		err = redis.GetRedisClient().HSet(redis.GS_USERBASE_INFO, strconv.Itoa(int(uid)), string(newval))

		if err != nil {
			logger.Error("RewardSign err=%v", err)
			return err
		}
		return nil
	}
	// *******************************

	for i := 0; i < len(rids); i++ {
		cmd := ""
		if rids[i] == common.Enum_Item_Coin {
			cmd = "update dtb_user_main set user_gold = user_gold + ? where uuid = ?"
			_, err := m_game_db.Exec(cmd, rnum[i], uid)
			if err != nil {
				logger.Notic("RewardTaskGruop failed err=%v", err)
				continue
			}

		} else if rids[i] == common.Enum_Item_Tili {
			cmd = "update dtb_user_main set user_tili = user_tili + ? where uuid = ?"
			_, err := m_game_db.Exec(cmd, rnum[i], uid)
			if err != nil {
				logger.Notic("RewardTaskGruop failed err=%v", err)
				continue
			}
		} else if rids[i] == common.Enum_Item_USD {
			cmd = "update dtb_user_main set user_dimond = user_dimond + ? where uuid = ?"
			_, err := m_game_db.Exec(cmd, rnum[i], uid)
			if err != nil {
				logger.Notic("RewardTaskGruop failed err=%v", err)
				continue
			}
		} else if rids[i] == common.Enum_Item_Plane {
			cmd = "update dtb_user_main set plan_num = plan_num + ? where uuid = ?"
			_, err := m_game_db.Exec(cmd, rnum[i], uid)
			if err != nil {
				logger.Notic("RewardTaskGruop failed err=%v", err)
				continue
			}
		} else if rids[i] == common.Enum_Item_Boom {
			cmd = "update dtb_user_main set boom_num = boom_num + ? where uuid = ?"
			_, err := m_game_db.Exec(cmd, rnum[i], uid)
			if err != nil {
				logger.Notic("RewardTaskGruop failed err=%v", err)
				continue
			}
		} else if rids[i] == common.Enum_Item_RainBow {
			cmd = "update dtb_user_main set rainbow_num = rainbow_num + ? where uuid = ?"
			_, err := m_game_db.Exec(cmd, rnum[i], uid)
			if err != nil {
				logger.Notic("RewardTaskGruop failed err=%v", err)
				continue
			}
		} else {
			logger.Notic("RewardTaskGruop cfg.ItemID failed rids=%v rnum=%v", rids, rnum)

		}
	}

	return nil
}

func GetNewGuideData(uid uint32) ([]*pb.NewGuideInfo, error) {
	var rtval []*pb.NewGuideInfo

	// *******************************
	if redis.GetRedisIsOpen() {

		val, err := redis.GetRedisClient().HGet(redis.GS_USERNEWGUIDE_DATA, strconv.Itoa(int(uid)))
		if err != nil {
			logger.Error("GetNewGuideData failed err=%v", err)
			return nil, err
		}
		err = json.Unmarshal([]byte(val), rtval)
		if err != nil {
			logger.Error("GetNewGuideData json failed err=%v", err)
			return nil, err
		}

		return rtval, nil
	}
	// *******************************

	cmd := "select guide_id,guide_state,guide_type from dtb_user_newguidelist where uuid = ?"
	rows, err := m_game_db.Query(cmd, uid)
	if rows != nil {
		defer rows.Close()
	}
	if err != nil {
		logger.Info("GetNewGuideData Query error:%v cmd:%v", err, cmd)
		return nil, err
	}
	for rows.Next() {
		var tmp pb.NewGuideInfo
		err = rows.Scan(&tmp.GuideId, &tmp.State, &tmp.Type)
		if err != nil {
			continue
		}
		rtval = append(rtval, &tmp)
	}

	return rtval, nil
}

func UpdateNewGuideInfo(info *pb.NewGuideInfo, uid uint32) error {
	if info == nil {
		logger.Notic("UpdateNewGuideInfo info nil")
		return errors.New("info nil")
	}

	// *******************************
	if redis.GetRedisIsOpen() {
		val, err := json.Marshal(info)
		if err != nil {
			logger.Error("UpdateNewGuideInfo err=%v", err)
			return err
		}

		err = redis.GetRedisClient().HSet(redis.GS_USERNEWGUIDE_DATA, strconv.Itoa(int(uid)), string(val))

		if err != nil {
			logger.Error("UpdateNewGuideInfo err=%v", err)
			return err
		}
		return nil
	}
	// *******************************

	cmd := "insert into dtb_user_newguidelist(uuid,guide_id,guide_state,guide_type,fin_time) values(?,?,?,?,?)"
	_, err := m_game_db.Exec(cmd, uid, info.GuideId, info.State, info.Type, time.Now().Unix())
	if err != nil {
		logger.Notic("UpdateNewGuideInfo failed err=%v", err)
		return err
	}
	return nil
}
